package com.google.code.lf.gfm.ui;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.FileFieldEditor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.eclipse.ui.progress.IProgressService;

import com.google.code.lf.gfm.GrisbiFileManager;
import com.google.code.lf.gfm.IGrisbiFileManager;
import com.google.code.lf.gfm.ui.error.ClientException;
import com.google.code.lf.gfm.ui.log.LogHelper;

//TODO Javadoc, commentaires
public class OptionsView extends ViewPart {

	public static final String ID = "com.google.code.lf.gfm.ui.view";

	private ScopedPreferenceStore preferenceStore;

	private final PreferencesPropertyChangeListener preferencesPropertyChangeListener = new PreferencesPropertyChangeListener();

	private FileFieldEditor fichierComptesFileFieldEditor;
	private FileFieldEditor fichierParametrageFileFieldEditor;
	private Button proceedBtn;

	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	@Override
	public void createPartControl(final Composite parent) {
		final GridLayout gridLayout = new GridLayout();
		parent.setLayout(gridLayout);
		setPartName("Options");

		// Récupération des préférences du plugin
		preferenceStore = (ScopedPreferenceStore) Activator.getDefault().getPreferenceStore();

		final String parcourir = "Parcourir...";

		// Choix du fichier de comptes
		final String fichierComptesPref = "fichierComptesPref";
		fichierComptesFileFieldEditor = new FileFieldEditor(fichierComptesPref, "Fichier de comptes :", true, FileFieldEditor.VALIDATE_ON_KEY_STROKE, parent);
		fichierComptesFileFieldEditor.setFileExtensions(new String[] { "*.gsb" });
		fichierComptesFileFieldEditor.setChangeButtonText(parcourir);
		fichierComptesFileFieldEditor.setEmptyStringAllowed(false);
		fichierComptesFileFieldEditor.getTextControl(parent).setToolTipText("Fichier de comptes Grisbi cible");
		// TODO Voir à améliorer cette idée d'image : disposer d'un icône + petit et d'une méthode helper pour récupérer l'image à partir d'un registre et de déclarations d'extensions (voire srcs pacifisc)
		//fileFieldEditor.getLabelControl(parent).setImage(Activator.getImageDescriptor("icons/grisbi_48x34.png").createImage());
		fichierComptesFileFieldEditor.setPreferenceStore(preferenceStore);
		preferenceStore.setDefault(fichierComptesPref, "Choisir un fichier .gsb   ->");
		fichierComptesFileFieldEditor.load(); // Récupération de la valeur depuis les préférences
		fichierComptesFileFieldEditor.setPropertyChangeListener(preferencesPropertyChangeListener);

		// Choix du fichier de paramétrage
		final String fichierParametragePref = "fichierParametragePref";
		fichierParametrageFileFieldEditor = new FileFieldEditor(fichierParametragePref, "Fichier de paramétrage :", true, FileFieldEditor.VALIDATE_ON_KEY_STROKE, parent);
		fichierParametrageFileFieldEditor.setFileExtensions(new String[] { "*.xml" });
		fichierParametrageFileFieldEditor.setChangeButtonText(parcourir);
		fichierParametrageFileFieldEditor.setEmptyStringAllowed(false);
		fichierParametrageFileFieldEditor.getTextControl(parent).setToolTipText("Fichier de paramétrage des règles à appliquer");
		fichierParametrageFileFieldEditor.setPreferenceStore(preferenceStore);
		preferenceStore.setDefault(fichierParametragePref, "Choisir un fichier .xml de paramétrage   ->");
		fichierParametrageFileFieldEditor.load(); // Récupération de la valeur depuis les préférences
		fichierParametrageFileFieldEditor.setPropertyChangeListener(preferencesPropertyChangeListener);

		// Label vide, pour le placement dans le layout
		final Label lbl = new Label(parent, SWT.NONE);
		lbl.setLayoutData(new GridData(SWT.CENTER));

		// Bouton de lancement
		proceedBtn = new Button(parent, SWT.PUSH);
		proceedBtn.setText("  Go! > ");
		proceedBtn.setToolTipText("Lancer le traitement");
		proceedBtn.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
		proceedBtn.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDown(final MouseEvent e) {
				if (e.count > 0 && e.button == 1) processFiles();
			}
		});
		proceedBtn.addTraverseListener(new TraverseListener() {
			@Override
			public void keyTraversed(final TraverseEvent e) {
				if (e.character == SWT.CR || e.character == ' ') processFiles();;
			}
		});

		final KeyAdapter processFilesOnEnterKeyAdapter = new KeyAdapter() {
			@Override
			public void keyPressed(final KeyEvent e) {
				if (e.character == SWT.CR) processFiles();
			}
		};
		fichierComptesFileFieldEditor.getTextControl(parent).addKeyListener(processFilesOnEnterKeyAdapter);
		fichierParametrageFileFieldEditor.getTextControl(parent).addKeyListener(processFilesOnEnterKeyAdapter);
	}

	private void processFiles() {
		// Si fichiers valides
		if (fichierComptesFileFieldEditor.isValid() && fichierParametrageFileFieldEditor.isValid()) {
			proceedBtn.setEnabled(false);
			// Gestion d'une barre de progression
			final IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
			try {
				progressService.run(false, true, new IRunnableWithProgress() {
					public void run(final IProgressMonitor monitor) {
						final int totalWork = 100;
						monitor.beginTask("Lancement du traitement...", totalWork);
						// Appel du plugin métier
						LogHelper.info("Traitement en cours...");
						if (!monitor.isCanceled()) GrisbiFileManager.main(new String[] { IGrisbiFileManager.pParam, fichierParametrageFileFieldEditor.getStringValue(), IGrisbiFileManager.aParam, fichierComptesFileFieldEditor.getStringValue() });
						monitor.worked(totalWork);
						LogHelper.info("Traitement terminé.");
						monitor.done();
					}
				});
			} catch (final InterruptedException ex) {
				throw new ClientException("Erreur lors du traitement.", ex, true);
			} catch (final InvocationTargetException ex) {
				throw new ClientException("Erreur lors du traitement: " + ex.getCause().getMessage(), ex, true);
			} finally {
				proceedBtn.setEnabled(true);
			}
		} else {
			// Fichiers invalides
			final StringBuilder msg = new StringBuilder("Le traitement ne peut être lancé que sur des fichiers valides.");
			if (!fichierComptesFileFieldEditor.isValid()) msg.append("\n- Le fichier de comptes est invalide.");
			if (!fichierParametrageFileFieldEditor.isValid()) msg.append("\n- Le fichier de paramétrage est invalide.");
			throw new ClientException(msg.toString());
		}
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	@Override
	public void setFocus() {
		fichierComptesFileFieldEditor.setFocus();
	}

	class PreferencesPropertyChangeListener implements IPropertyChangeListener {
		@Override
		public void propertyChange(final PropertyChangeEvent event) {
			// Gestion des préférences : saisie correcte -> on enregistre, saisie incorrecte -> on recharge la dernière bonne valeur connue
			final String eventFieldEditorValueKey = "field_editor_value";
			boolean preferencesNeedSave = false;
			if (event.getSource().equals(fichierComptesFileFieldEditor) && event.getProperty().equals(eventFieldEditorValueKey) && !event.getNewValue().equals(event.getOldValue())) {
				if (fichierComptesFileFieldEditor.isValid()) {
					fichierComptesFileFieldEditor.store();
					preferencesNeedSave = true;
					LogHelper.trace(new StringBuilder(fichierComptesFileFieldEditor.getLabelText()).append(": Fichier validé: ").append(fichierComptesFileFieldEditor.getStringValue()).append(".").toString());
				}
				else {
					fichierComptesFileFieldEditor.load();
					LogHelper.trace(new StringBuilder(fichierComptesFileFieldEditor.getLabelText()).append(": Fichier invalide, on recharge la dernière bonne valeur connue.").toString());
				}
			}
			if (event.getSource().equals(fichierParametrageFileFieldEditor) && event.getProperty().equals(eventFieldEditorValueKey) && !event.getNewValue().equals(event.getOldValue())) {
				if (fichierParametrageFileFieldEditor.isValid()) {
					fichierParametrageFileFieldEditor.store();
					preferencesNeedSave = true;
					LogHelper.trace(new StringBuilder(fichierParametrageFileFieldEditor.getLabelText()).append(": Fichier validé: ").append(fichierParametrageFileFieldEditor.getStringValue()).append(".").toString());
				}
				else {
					fichierParametrageFileFieldEditor.load();
					LogHelper.trace(new StringBuilder(fichierParametrageFileFieldEditor.getLabelText()).append(": Fichier invalide, on recharge la dernière bonne valeur connue.").toString());
				}
			}

			// Sauvegarde des préférences
			if (preferencesNeedSave) {
				try {
					preferenceStore.save();
					LogHelper.trace("Préférences sauvegardées.");
				} catch (final IOException e) {
					throw new ClientException("Erreur à la sauvegarde des préférences.", e);
				}
			}
		}
	}

}
